<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.4.1 / SVN信息: $Id: class.JCAT_ArchiveModel.php 1510 2009-03-23 06:51:00Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/





/**
 * What's this Class ?
 *
 * @author		alee
 * @access		public
 */
class JCAT_ArchiveModel extends JCAT_Model
{


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName=''	string	What's this Parameter ?
	 * @param	$sPath=''	string	What's this Parameter ?
	 * @return	void
	 */
	public function JCAT_ArchiveModel( $sName='', $sPath='' ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		JCAT_ASSERT::ASSERT_STRING($sPath) ;
		
		$this->JCAT_Model($sName) ;
		
		if($sPath)
			$this->SetPath($sPath) ;
	}
	
	
	/**
	 * 模型是否存在
	 * 
	 * @access	public
	 * @param	$bRequery=false		bool	对于高级模型（如数据库模型），此 查询操作可能  会存在一定性能代价 ，该参数允许缓存查询结果
	 * @return	bool
	 */
	public function IsExists( $bRequery=false )
	{
		$sPath = $this->GetPath() ;
		if( !$sPath )
			return false ;

		return is_file($sPath) ;
	}
	
	
	
	/**
	 * 对模型进行序列化，并返回序列化字串
	 * 
	 * @access	public
	 * @return	string
	 */
	public function SerializeData()
	{
		// 本模型的 数据
		$arrSerialize[ self::Key_Data ] = $this->GetDatas() ;

		// 子模型的数据
		$aChildIterator = $this->CreateModelIterator() ;
		$aChildIterator->First() ;
		while( !$aChildIterator->IsDone() )
		{
			// 将  整数参数转换为 
			$sName = $aChildIterator->CurrentKey() ;
			if( is_int($sName) )
			{
				$sName = strval($sName) ;
			}
			
			$aChildDoc = $aChildIterator->Current() ;
			
			$arrData['class'] = get_class($aChildDoc) ;
			$arrData['name'] = $sName ;
			$arrData['data'] = $this->SerializeChildModel($arrData['name'],$aChildDoc) ;
			
			$arrSerialize[ self::Key_Children ][] = $arrData ;

			$aChildIterator->Next() ;
		}
		// 序列化
		$sSerialize = serialize($arrSerialize) ;
		
		// 压缩
		$sSerialize = gzcompress( $sSerialize, 9 ) ;
		
		// 编码
		$sSerialize = JCAT_Encode::Encode($sSerialize,$this->GetByteLenPerLine()) ;
		
		// 打包 返回 
		return self::GenerateModelClassTagInSerializeData( get_class($this) )."\r\n".$sSerialize ;
	}

	/**
	 * 对模型 还原
	 * 
	 * @access	public
	 * @param 	$sSerializeByte		string		经过  SerializeData() 序列化的字串
	 * @return	bool
	 */
	public function UnserializeData( $sSerializeByteIn )
	{
		// 移除 模型类 类名记录
		$sSerializeByte = $sSerializeByteIn ;
		self::ExtractModelClassInSerializeData($sSerializeByte) ;
		
		// 解码
		$sSerializeByte = JCAT_Encode::Decode($sSerializeByte) ;
		
		// 解压缩
		$sSerializeByte = gzuncompress($sSerializeByte) ;
				
		// 恢复 本模型数据
		$arrSerialize = unserialize($sSerializeByte) ;
		if( !isset($arrSerialize[ self::Key_Data ]) )
		{
			throw new JCAT_Exception(JCAT_Language::SentenceEx('反序列化失败（数据可能被损坏）：在传入的序列化字节串中没有找到本模型数据。','JCAT',null),__macro_exception_code__) ;
			return false ;
		}

		$this->SetDatas( $arrSerialize[ self::Key_Data ] ) ;
		
		// 子模型的数据
		if( isset($arrSerialize[ self::Key_Children ]) )
		{
			foreach ($arrSerialize[ self::Key_Children ] as $arrData)
			{			
				$this->UnserializeChildModel($arrData['name'],$arrData['class'],$arrData['data']) ;
			}
		}
		
		return true ;
	}

	static function ExtractModelClassInSerializeData( $sByteInd )
	{
		$sModelClassName = '' ;
	
		$sReg = '/^<<\{\{ModelClass:+([^\}]+)\}\}>>/' ;
		$sRegGroup = 1 ;
		if( preg_match($sReg,$sByteInd,$arrRes) )
		{
			$sModelClassName = $arrRes[$sRegGroup] ;
			
			$sByteInd = preg_replace($sReg,'',$sByteInd) ;
			
			$sByteInd = trim($sByteInd) ;
		}
		
		return $sModelClassName? $sModelClassName: null ;
	}

	static function GenerateModelClassTagInSerializeData($sModelClass)
	{
		JCAT_ASSERT::ASSERT_STRING($sModelClass) ;
		return "<<{{ModelClass:{$sModelClass}}}>>" ;
	}
	/**
	 * what's this
	 * 
	 * @access	protected
	 * @param	 $Name[in,out]		string					what's this
	 * @param	$aChildDoc			JCAT_ArchiveModel	what's this
	 * @return	string
	 */
	protected function SerializeChildModel( $sName,JCAT_IModel $aChildDoc)
	{
		JCAT_ASSERT::ASSERT_INSTANCE($aChildDoc,'JCAT_IModel') ;
		JCAT_ASSERT::ASSERT_STRING($sName) ;

		// JCAT_ArchiveModel 类型的  子模型
		if( JCAT_Global::IsKindOf($aChildDoc,__CLASS__) )
		{
			return $aChildDoc->SerializeData() ;
		}
		
		// 未知 类型 模型的  缺省方式
		else
		{
			return serialize($aChildDoc) ;
		}
	}
	
	/**
	 * what's this
	 * 
	 * @access	protected
	 * @param	 $sName[in,out]	string					what's this
	 * @param	$sByteData			string					what's this
	 * @return	JCAT_IModel, null
	 */
	protected function UnserializeChildModel( $sName, $sClass, $sByteData )
	{
		JCAT_ASSERT::ASSERT_STRING($sName) ;
		JCAT_ASSERT::ASSERT_STRING($sByteData) ;
		
		// 取得子模型
		$aChildDoc = $this->GetModel($sName) ;
		
		// 子模型类名
		if($aChildDoc)
		{
			$sClassName = get_class($aChildDoc) ;
		}
		else
		{
			$sClassName = $sClass ;
		}

		// 如果是 静态结构模型 抛出 模型损坏 异常
		// TODO ... ...
		
		JCAT_ASSERT::ASSERT_STRING($sClassName) ;

		// JCAT_ArchiveModel 类型的  子模型
		if( JCAT_Global::IsKindOf($sClassName,__CLASS__) )
		{
			// 创建新模型
			if( !$aChildDoc )
			{
				$aChildDoc = new JCAT_ArchiveModel($sName) ;
				$this->AddModel($aChildDoc,$sName) ;
			}
			
			$sPath = $this->GetPath() ;
			if($sPath!==null)
			{
				$aChildDoc->SetPath($sPath) ;
			}
			
			// 反序列化
			if( !$aChildDoc->UnserializeData($sByteData) )
			{
				return false ;
			}
		}

		// 未知 类型 模型的  缺省方式
		else
		{
			$aChildDoc = @unserialize($sByteData) ;		
			$this->AddModel($aChildDoc,$sName) ;
		}
		
		return true ;
	}
	
	/**
	 * 返回模型的路径
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetPath()
	{
		return $this->sPath ;
	}
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$sPath		string			what's this
	 * @return	array
	 */
	public function SetPath($sPath)
	{
		JCAT_ASSERT::ASSERT_STRING($sPath);
		JCAT_ASSERT::ASSERT_( !is_dir($sPath), JCAT_Language::SentenceEx('正在设置的模型路径，是一个存在的目录。','JCAT',null) );
		$this->sPath = $sPath ;
		
		// 为子模型设置路径
		$aIterator = $this->CreateModelIterator();
		$aIterator->First() ;
		while( !$aIterator->IsDone() )
		{
			$aChildDoc = $aIterator->Current() ;
			
			if( JCAT_Global::IsKindOf($aChildDoc,'JCAT_ArchiveModel') )
			{
				$aChildDoc->SetPath($sPath) ;
			}
			
			$aIterator->Next() ;
		}
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Load()
	{
		$sPath = $this->GetPath() ;
		JCAT_ASSERT::ASSERT_FILE($sPath,JCAT_Language::SentenceEx('无法读取模型：尚未设置模型路径。','JCAT',null));
		
		$sByteContents = $this->LoadFromFile( $sPath ) ;

		$this->UnserializeData($sByteContents) ;
	}


	
	/**
	 * 从文件中读取内容
	 * 
	 * @access	protected
	 * @param	$sPath		string		what's this
	 * @return	string
	 */
	protected function LoadFromFile( $sPath )
	{
		JCAT_ASSERT::ASSERT_FILE($sPath);
		
		return file_get_contents($sPath) ;
	}
	
	
	/**
	 * 将序列化以后的内容存入到 模型
	 * 
	 * @access	protected
	 * @param	$sPath				文件路径
	 * @param	$sByteContents		字节内容
	 * @param	$bAsBinary			作为二进制存储
	 * @return	bool
	 */
	protected function SaveToFile( $sPath, $sByteContents, $bAsBinary=false )
	{			
		return file_put_contents($sPath,$sByteContents) ;		
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Save()
	{
		$sPath = $this->GetPath() ;
		JCAT_ASSERT::ASSERT_FILE($sPath) ;
		
		// 执行序列化
		$sByteContents = $this->SerializeData() ;
			
		// 保存模型到文件
		return $this->SaveToFile($sPath,$sByteContents) ;
	}

	


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Create()
	{
		// 创建一个新模型
		$this->CreateNewModel() ;
		
		// 保存数据
		return $this->Save() ;
	}
	
	
	/**
	 * What's this Method ?
	 * 
	 * @access	protected
	 * @return	void
	 */
	protected function CreateNewModel()
	{
		$sPath = $this->GetPath() ;
		JCAT_ASSERT::ASSERT_( !empty($sPath), JCAT_Language::SentenceEx('无法创建新模型：尚未设置模型路径。','JCAT',null) );
		
		if( is_file($sPath) )
			throw new JCAT_Exception(JCAT_Language::SentenceEx('无法创建新模型：文件已经存在。“%s”','JCAT',null,$sPath),__macro_exception_code__) ;

		// 创建文件
		if( is_dir($sPath) )
			throw new JCAT_Exception(JCAT_Language::SentenceEx('无法保存模型：设置的模型路径是一个存在的目录：%s','JCAT',null,$sPath),__macro_exception_code__) ;
		JCAT_File::CreateFile($sPath) ;
	}
	
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Delete()
	{
		$sPath = $this->GetPath() ;
		JCAT_ASSERT::ASSERT_FILE( $sPath, JCAT_Language::SentenceEx('无法删除模型：尚未设置模型路径。','JCAT',null) );
		
		unlink($sPath) ;
	}


	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$nByteLenPerLine	int			what's this
	 * @return	old_value
	 */
	public function SetByteLenPerLine( $nByteLenPerLine )
	{
		$old_value = $this->nByteLenPerLine ;
		$this->nByteLenPerLine = $nByteLenPerLine ;
		return $old_value ;
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @return	int
	 */
	public function GetByteLenPerLine()
	{
		return $this->nByteLenPerLine ;
	}


	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sPath ;


	const Key_Data = 'Data' ;
	const Key_Children = 'Children' ;
	
	
	
	protected $nByteLenPerLine = 0 ;
}



?>